package inventory

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	"bgs/grpc/imp/enums"
	nsqpUtil "bgs/nsqp/util"
	enforcementService "bgs/service/enforcement"
	ledgerService "bgs/service/ledger"
	"bgs/util"
	wxpMinaService "bgs/wxp/mina"
	"bytes"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
)

// ProcessOrderUpdateMessage 履约单状态更新消息体
type ProcessOrderUpdateMessage struct {
	OrderNumber    string `json:"order_number"`     // 履约单号（推荐使用），传入该参数则无需外部订单号&订单类型
	ExtOrderNumber string `json:"ext_order_number"` // 上游系统请求订单号（与类型共用，上游系统自己确保不重复，如果匹配到重复单时报错不解冻）
	Status         int32  `json:"status"`           // 10~待备货(已付款)，11~待自提，20~待发货，21~已发货待签收，30~待退货，32~已拒绝接收，33~退货完成，98~正向已完成（自提完成/收货完成），99~已取消
	DeliverType    int32  `json:"deliver_type"`     // 配送模式0~自提，1~同城，2~普快
	DeliverMemo    struct {
		Platform         string `json:"platform"`
		PlatformOrderNum string `json:"platform_order_num"`
		ExtractKey       string `json:"extract_key"`
		DeadlineTime     string `json:"deadline_time"`
		PickupAddress    string `json:"pickup_address"`
		DeliverTime      string `json:"deliver_time"` // 2020-06-30 15:00:00
		PrepareTime      string `json:"prepare_time"` // 2020-06-30 15:00:00
	} `json:"deliver_memo"`
	Timestamp int64 `json:"timestamp"` // 更新时间戳
	Source    int32 `json:"source"`    // 2~商城履约订单(外部订单号为商城单号)，3~星团履约订单（外部订单号为星团单号）
}

// ProcessOrderUpdateHandler inventory process order update message handler
type ProcessOrderUpdateHandler struct {
	dao                *db.PgDao
	slog               *zap.SugaredLogger
	topic              string
	failover           *nsqpUtil.NsqFailover
	enforcementService *enforcementService.EnforcementServiceImp
	ledgerService      *ledgerService.LedgerServiceImp
	wxpMinaService     *wxpMinaService.MinaServiceImp
}

// NewProcessOrderUpdateHandler create a new handler for process order update
func NewProcessOrderUpdateHandler(pgdao *db.PgDao, slog *zap.SugaredLogger,
	topic string,
	failover *nsqpUtil.NsqFailover,
	enforcementService *enforcementService.EnforcementServiceImp,
	ledgerService *ledgerService.LedgerServiceImp,
	wxpMinaService *wxpMinaService.MinaServiceImp,
) *ProcessOrderUpdateHandler {
	return &ProcessOrderUpdateHandler{
		dao:                pgdao,
		slog:               slog.With("module", "ProcessOrderUpdateHandler"),
		topic:              topic,
		failover:           failover,
		enforcementService: enforcementService,
		ledgerService:      ledgerService,
		wxpMinaService:     wxpMinaService,
	}
}

// HandleMessage implements the Handler interface.
func (h *ProcessOrderUpdateHandler) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	h.slog.Infof("message=>%s", string(m.Body))

	v := &ProcessOrderUpdateMessage{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析信息[ProcessOrderUpdateMessage]: %s", decodeErr.Error())
	}

	reqID := strconv.FormatInt(v.Timestamp, 10)
	slog := h.slog.With("reqID", reqID)
	// 将来抽象到对应的业务组件
	ctx := context.WithValue(context.Background(), util.RequestID{}, reqID)

	var err error
	defer h.failover.BackupSubMsgWhenHandleFail(ctx, &err, nsqpUtil.BackupSubMsgParam{
		Ts:    v.Timestamp,
		Topic: h.topic,
		Mbody: m.Body,
	})

	isPrepared := v.Status == int32(enums.EnumProcessOrderStatusWaitPickup)
	isDelivered := v.Status == int32(enums.EnumProcessOrderStatusDelivered)
	isFinished := v.Status == int32(enums.EnumProcessOrderStatusFinished)
	orderSerialNumber := v.ExtOrderNumber

	if isPrepared || isDelivered || isFinished {
		err = h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
			if isPrepared {
				prepared, err := util.StringfToGoTime(v.DeliverMemo.PrepareTime, util.LayoutSecond)
				if err != nil {
					return err
				}
				err = h.enforcementService.DoAfterOrderPrepared(ctx, q, enforcementService.AfterOrderPreparedParam{
					OrderSerialNumber: orderSerialNumber,
					Prepared:          prepared,
					PickupCode:        v.DeliverMemo.ExtractKey,
					PickupAddress:     v.DeliverMemo.PickupAddress,
					PickupDeadline:    v.DeliverMemo.DeadlineTime,
				})
				if err != nil {
					return err
				}

				// 发送 订单状态提醒, 到店自提提醒
			}

			if isDelivered {
				delivered, err := util.StringfToGoTime(v.DeliverMemo.DeliverTime, util.LayoutSecond)
				if err != nil {
					return err
				}
				err = h.enforcementService.DoAfterOrderDelivered(ctx, q, enforcementService.AfterOrderDeliveredParam{
					OrderSerialNumber: orderSerialNumber,
					Delivered:         delivered,
					Platform:          v.DeliverMemo.Platform,
					PlatformOrderNum:  v.DeliverMemo.PlatformOrderNum,
				})
				if err != nil {
					return err
				}
			}

			if isFinished {
				// 获取分账佣金 合并事务
				ledgerRequest, sqlErr := q.GetLedgerRequestByOrderSerialNumberAndProfitTrigger(ctx, sqlc.GetLedgerRequestByOrderSerialNumberAndProfitTriggerParams{
					OrderSerialNumber: orderSerialNumber,
					ProfitTrigger: string(sqlc.EmProfitTriggerAtOrderStatusToFinish),
				})
				if sqlErr != nil {
					if sql.ErrNoRows == sqlErr {
						slog.Infof("在订单完成场景没有找到分账申请,无须提交分账")
					} else {
						err = sqlErr
					}
					return
				}
				slog.Infof("获取在订单完成场景的分账请求信息成功")

				err = h.ledgerService.RequestToProxy(ctx, q, &ledgerRequest)
				if err != nil {
					slog.Infof("订单(%s)在订单完成场景的分账请求失败:%s", orderSerialNumber, err.Error())
				}
			}
			return
		})
		if err != nil {
			return err
		}
		slog.Infof("消息[ProcessOrderUpdateMessage]处理成功")
		// 发送=>[订单状态提醒, 到店自提提醒]
		if isPrepared {
			notifyParam, genErr := h.enforcementService.GenOrderPreparedNotifyMessage(ctx, h.dao.Q, orderSerialNumber)
			if genErr != nil {
				slog.Errorf("生成备货消息失败:%s", genErr.Error())
			}
			slog.Infof("ProcessOrderUpdateHandler notifiyParam:%#v", notifyParam)
			sendErr := h.wxpMinaService.SendNotify(ctx, &notifyParam)
			if sendErr != nil {
				slog.Errorf("发送mina到店自提提醒失败:%s", sendErr.Error())
			}
		}
		if isDelivered {
			notifyParam, genErr := h.enforcementService.GenOrderDeliveredNotifyMessage(ctx, h.dao.Q, orderSerialNumber)
			if genErr != nil {
				slog.Errorf("生成发货消息失败:%s", genErr.Error())
			}
			sendErr := h.wxpMinaService.SendNotify(ctx, &notifyParam)
			if sendErr != nil {
				slog.Errorf("发送mina订单状态提醒失败:%s", sendErr.Error())
			}
		}

	} else {
		slog.Infof("not need for ProcessOrderUpdateMessage.status =>%d", v.Status)
	}

	// if isFinished {

	// }
	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
